#pragma once
#include "tv_types.h"

class EXPORTCLASS CTVMathLibrary
{
public:
	int iMathLibraryIndex;
	CTVMathLibrary(void);
	~CTVMathLibrary(void); 

	cTV_3DVECTOR MoveAroundPoint(cTV_3DVECTOR* vOrigin, float fRadius, float fHorizAngle, float fVertAngle);
	cTV_3DVECTOR IntersectionXZPlane(float fY, cTV_3DVECTOR* vPointAbove, cTV_3DVECTOR* vPointBelow);
	void TVMatrixTranslation(cTV_3DMATRIX* retOutMatrix, float fTranslationX, float fTranslationY, float fTranslationZ);
	void TVMatrixScaling(cTV_3DMATRIX* retOutMatrix, float fScalingX, float fScalingY, float fScalingZ);
	void TVMatrixIdentity(cTV_3DMATRIX* retOutMatrix);
	void TVMatrixReflect(cTV_3DMATRIX* retOutMatrix, cTV_PLANE* pPlane);
	void TVMatrixShadow(cTV_3DMATRIX* retOutMatrix, cTV_4DVECTOR* vLightVector, cTV_PLANE* pShadowPlane);
	void TVMatrixRotationYawPitchRoll(cTV_3DMATRIX* retOutMatrix, float fAngleYaw, float fAnglePitch, float fAngleRoll);
	void TVMatrixRotationX(cTV_3DMATRIX* retOutMatrix, float fAngleDegOrRad);
	void TVMatrixRotationY(cTV_3DMATRIX* retOutMatrix, float fAngleDegOrRad);
	void TVMatrixRotationZ(cTV_3DMATRIX* retOutMatrix, float fAngleDegOrRad);
	void TVMatrixInverse(cTV_3DMATRIX* retOutMatrix, float* retDeterminant, cTV_3DMATRIX* mMat);
	void TVMatrixTranspose(cTV_3DMATRIX* retOutMatrix, cTV_3DMATRIX* mMat);
	void TVMatrixRotationQuaternion(cTV_3DMATRIX* retOutMatrix, cTV_3DQUATERNION* qQuat);
	void TVMatrixMultiply(cTV_3DMATRIX* retOutMatrix, cTV_3DMATRIX* mMat1, cTV_3DMATRIX* mMat2);
	void TVMatrixRotationAxis(cTV_3DMATRIX* retOutMatrix, cTV_3DVECTOR* vAxis, float fAngle);
	void TVVec3Hermite(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vT1, cTV_3DVECTOR* vV2, cTV_3DVECTOR* vT2, float s)	   ;
	float TVVec3Dot(cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	void TVVec3CatmulRom(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV0,cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2, cTV_3DVECTOR* vV3, float s);
	void TVVec3BaryCentric(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2, cTV_3DVECTOR* vV3, float f, float g);
	void TVVec3Add(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	void TVVec3Scale(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV, float s);
	void TVVec3Normalize(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV);
	void TVVec3Minimize(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	void TVVec3Maximize(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	void TVVec3Lerp(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2, float s);
	float TVVec3LengthSq(cTV_3DVECTOR* vV);
	float TVVec3Length(cTV_3DVECTOR* vV);
	void TVVec3Cross(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	void TVVec3MultiplyAdd(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, float fScale, cTV_3DVECTOR* vAdd);
	void TVVec3TransformNormal(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV, cTV_3DMATRIX* mMat);
	void TVVec3Subtract(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	void TVVec3Transform(cTV_4DVECTOR* retOutVector, cTV_3DVECTOR* vV, cTV_3DMATRIX* mMat);
	void TVVec3TransformCoord(cTV_3DVECTOR* retOutVector, cTV_3DVECTOR* vV, cTV_3DMATRIX* mMat);
	void TVVec2Add(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2);
	void TVVec2BaryCentric(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2, cTV_2DVECTOR* vV3, float f, float g);
	void TVVec2CatmulRom(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV0,cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2, cTV_2DVECTOR* vV3, float s);
	float TVVec2Dot(cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2);
	void TVVec2Hermite(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV1, cTV_2DVECTOR* vT1, cTV_2DVECTOR* vV2, cTV_2DVECTOR* vT2, float s);
	float TVVec2Length(cTV_2DVECTOR* vV);
	float TVVec2LengthSq(cTV_2DVECTOR* vV);
	void TVVec2Lerp(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2, float s);
	void TVVec2Maximize(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2);
	void TVVec2Minimize(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2);
	void TVVec2Normalize(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV);
	void TVVec2Scale(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV, float s);
	void TVVec2Subtract(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2);
	void TVVec2Transform(cTV_4DVECTOR* retOutVector, cTV_2DVECTOR* vV, cTV_3DMATRIX* mMat);
	void TVVec2TransformCoord(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV, cTV_3DMATRIX* mMat);
	void TVVec2TransformNormal(cTV_2DVECTOR* retOutVector, cTV_2DVECTOR* vV, cTV_3DMATRIX* mMat);	
	void TVVec4Add(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2);
	void TVVec4BaryCentric(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2, cTV_4DVECTOR* vV3, float f, float g);
	void TVVec4CatmulRom(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV0,cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2, cTV_4DVECTOR* vV3, float s);
	float TVVec4Dot(cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2);
	void TVVec4Hermite(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV1, cTV_4DVECTOR* vT1, cTV_4DVECTOR* vV2, cTV_4DVECTOR* vT2, float s);
	float TVVec4Length(cTV_4DVECTOR* vV);
	float TVVec4LengthSq(cTV_4DVECTOR* vV);
	void TVVec4Lerp(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2, float s);
	void TVVec4Maximize(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2);
	void TVVec4Minimize(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2);
	void TVVec4Normalize(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV);
	void TVVec4Scale(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV, float s);
	void TVVec4Subtract(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2);
	void TVVec4Transform(cTV_4DVECTOR* retOutVector, cTV_4DVECTOR* vV, cTV_3DMATRIX* mMat);
	void TVQuaternionBaryCentric(cTV_3DQUATERNION* retOutQuat, cTV_3DQUATERNION* qQ1, cTV_3DQUATERNION* qQ2, cTV_3DQUATERNION* qQ3, float f, float g);
	void TVQuaternionConjugate(cTV_3DQUATERNION* retOutQuat, cTV_3DQUATERNION* qQuat);
	float TVQuaternionDot(cTV_3DQUATERNION* qQuat1, cTV_3DQUATERNION* qQuat2);
	void TVQuaternionExp(cTV_3DQUATERNION* retOutQuat, cTV_3DQUATERNION* qQuat);
	void TVQuaternionIdentity(cTV_3DQUATERNION* retOutQuat);
	void TVQuaternionInverse(cTV_3DQUATERNION* retOutQuat, cTV_3DQUATERNION* pQuat);
	float TVQuaternionLength(cTV_3DQUATERNION* retOutQuat);
	float TVQuaternionLengthSq(cTV_3DQUATERNION* retOutQuat);
	void TVQuaternionLn(cTV_3DQUATERNION* retOutQuat, cTV_3DQUATERNION* qQuat);
	void TVQuaternionMultiply(cTV_3DQUATERNION* retOutQuat, cTV_3DQUATERNION* qQuat1, cTV_3DQUATERNION* qQuat2);
	void TVQuaternionNormalize(cTV_3DQUATERNION* retOutQuat, cTV_3DQUATERNION* qQuat);
	void TVQuaternionRotationAxis(cTV_3DQUATERNION* retOutQuat, cTV_3DVECTOR* vAxis, float fAngleRadOrDeg);
	void TVQuaternionRotationMatrix(cTV_3DQUATERNION* retOutQuat, cTV_3DMATRIX* mMat);
	void TVQuaternionRotationYawPitchRoll(cTV_3DQUATERNION* retOutQuat, float fAngleYaw, float fAnglePitch, float fAngleRoll);
	float TVPlaneDot(cTV_PLANE* pPlane, cTV_4DVECTOR* vVec4);
	float TVPlaneDotCoord(cTV_PLANE* pPlane, cTV_3DVECTOR* vVec3);
	float TVPlaneDotNormal(cTV_PLANE* pPlane, cTV_3DVECTOR* vVec3);
	void TVPlaneFromPointNormal(cTV_PLANE* retOutPlane, cTV_3DVECTOR* vPoint, cTV_3DVECTOR* vNormal);
	void TVPlaneFromPoints(cTV_PLANE* retOutPlane, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2, cTV_3DVECTOR* vV3);
	void TVPlaneIntersectLine(cTV_3DVECTOR* retOutIntersection, cTV_PLANE* pPlane, cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	void TVPlaneNormalize(cTV_PLANE* retOutPlane, cTV_PLANE* pPlane);
	void TVPlaneScale(cTV_PLANE* retOutPlane, cTV_PLANE* pPlane, float fScale);
	void TVPlaneTransform(cTV_PLANE* retOutPlane, cTV_PLANE* pPlane, cTV_3DMATRIX* mMat);
	cTV_3DVECTOR VAdd(cTV_3DVECTOR* v1, cTV_3DVECTOR* v2);
	cTV_3DVECTOR VSubtract(cTV_3DVECTOR* v1, cTV_3DVECTOR* v2);
	cTV_3DVECTOR VScale(cTV_3DVECTOR* v, float fScale);
	float VDotProduct(cTV_3DVECTOR* v1, cTV_3DVECTOR* v2);
	cTV_3DVECTOR VCrossProduct(cTV_3DVECTOR* v1, cTV_3DVECTOR* v2);
	cTV_3DVECTOR VNormalize(cTV_3DVECTOR* v);
	float VModulus(cTV_3DVECTOR* v1);
	float VLength(cTV_3DVECTOR* v);
	bool VCompare(cTV_3DVECTOR* v1, cTV_3DVECTOR* v2);
	bool VCompare2(cTV_3DVECTOR* v1, cTV_3DVECTOR* v2, float fEpsilon);
	float GetDistance2D(float fX1, float fY1, float fX2, float fY2);
	float GetDistance3D(float fX1, float fY1, float fZ1, float fX2, float fY2, float fZ2);
	float GetDistanceVec2D(cTV_2DVECTOR* v1, cTV_2DVECTOR* v2);
	float GetDistanceVec3D(cTV_3DVECTOR* v1, cTV_3DVECTOR* v2);
	float Direction2Ang(float fX, float fZ); 
	float Deg2Rad(float fAngleInDegrees);
	float Rad2Deg(float fAngleInRadians); 
	cTV_3DVECTOR VMultiply(cTV_3DVECTOR* v, float fScale);
	bool Project3DPointTo2D(cTV_3DVECTOR* vPoint, float* ret_x, float* ret_y, bool bFrontOnly );
	void TVColorAdd(cTV_COLOR* retOutColor, cTV_COLOR* cColor1, cTV_COLOR* cColor2);
	void TVColorAdjustContrast(cTV_COLOR* retOutColor, cTV_COLOR* cSourceColor, float fContrast);
	void TVColorAdjustSaturation(cTV_COLOR* retOutColor, cTV_COLOR* cSourceColor, float fSaturation);
	void TVColorLerp(cTV_COLOR* retOutColor, cTV_COLOR* cColor1, cTV_COLOR* cColor2, float fS);
	void TVColorModulate(cTV_COLOR* retOutColor, cTV_COLOR* cColor1, cTV_COLOR* cColor2);
	void TVColorNegative(cTV_COLOR* retOutColor, cTV_COLOR* cColor);
	void TVColorSubtract(cTV_COLOR* retOutColor, cTV_COLOR* cColor1, cTV_COLOR* cColor2);
	void TVColorScale(cTV_COLOR* retOutColor, cTV_COLOR* cColor, float fScale);
	void GetMousePickVectors(float fMouseX, float fMouseY, cTV_3DVECTOR* retNearStartRay, cTV_3DVECTOR* retFarEndRay); 

	float ATan2(float fY, float fX);
	float ASin(float fX);
	float ACos(float fX);
	float ATan(float fX);
	void TVMatrixLerp(cTV_3DMATRIX* retOut, cTV_3DMATRIX* mIn1, cTV_3DMATRIX* mIn2, float t);
	void TVMatrixLookAt(cTV_3DMATRIX* retOut, cTV_3DVECTOR* vStart, cTV_3DVECTOR* vLookAtPoint, cTV_3DVECTOR* vUpVector); 
	void TVConvertQuaternionToMatrix(cTV_3DMATRIX* retOut, cTV_3DQUATERNION* qQuat);
	void TVConvertMatrixToQuaternion(cTV_3DQUATERNION* retOut, cTV_3DMATRIX* mMat);
	float TVVec3Distance(cTV_3DVECTOR* vV1, cTV_3DVECTOR* vV2);
	float TVVec2Distance(cTV_2DVECTOR* vV1, cTV_2DVECTOR* vV2);
	float TVVec4Distance(cTV_4DVECTOR* vV1, cTV_4DVECTOR* vV2);

	void TVQuaternionLerp(cTV_3DQUATERNION* retQuatResult, cTV_3DQUATERNION* qQ1, cTV_3DQUATERNION* qQ2, float t);
	void TVQuaternionSlerp(cTV_3DQUATERNION* retQuatResult, cTV_3DQUATERNION* qQ1, cTV_3DQUATERNION* qQ2, float t);

	void TVMatrixDecompose(cTV_3DVECTOR* retOutScale, cTV_3DQUATERNION* retOutQuaternion, cTV_3DVECTOR* retOutTranslation, cTV_3DMATRIX* mMatrix);
	void TVMatrixClipPlaneProjection(cTV_3DMATRIX* retMatrix, cTV_3DMATRIX* mCameraMatrix, cTV_3DMATRIX* mOldProjection, cTV_PLANE* mReflectionPlane);
	void TVMatrixInvertReflectCulling(cTV_3DMATRIX* mFixedMatrix, cTV_3DMATRIX* mSourceMatrix);

	void TVVec3Rotate(cTV_3DVECTOR* retOutVector,cTV_3DVECTOR* vVector,  float fYaw, float fPitch, float fRoll);
	void TVVec2Rotate(cTV_2DVECTOR* retOutVector,cTV_2DVECTOR* vVector,  float fYaw, float fPitch, float fRoll);
	void TVVec4Rotate(cTV_4DVECTOR* retOutVector,cTV_4DVECTOR* vVector,  float fYaw, float fPitch, float fRoll);

	void TVEulerAnglesFromMatrix(cTV_3DVECTOR* retOutVector, cTV_3DMATRIX* mMatrix);
	bool Project2DPointTo3D(float fX, float fY, float fFarPlaneRatio, cTV_3DVECTOR* retvVector);

	int SortVectorList(cTV_3DVECTOR* vReferencePoint, int iNumVectors, cTV_3DVECTOR* pVertexArray, int* retSortedIndicesListArray, bool bBackwards = false);
};
